/***************************************************************
*  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
*  All rights reserved.
*
*  This file is part of the GroupMe! Project. Source code of 
*  this project is closed and redistribution of this code is
*  prohibited. 
*  
*  Contact: http://www.groupme.net
*
*  This copyright notice MUST APPEAR in all copies of the file!
***************************************************************/
package net.groupme.controller;

import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.groupme.api.API_CONSTANTS;
import net.groupme.controller.oauth.OAuthProtocol;
import net.groupme.controller.oauth.OAuthProvider;
import net.groupme.exceptions.AddingResourceFailedException;
import net.groupme.exceptions.UserNotExistingException;
import net.groupme.group.GroupManager;
import net.groupme.gui.constants.VIEW_VOCABULARY;
import net.groupme.model.ObjectFactory;
import net.groupme.model.Resource;
import net.groupme.model.ResourceVisualization;
import net.groupme.model.User;
import net.groupme.user.UserManager;
import net.groupme.utils.HTTPUtilities;
import net.groupme.utils.sql.UserQueryUtility;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthMessage;
import net.oauth.server.OAuthServlet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.groupme.model.light.Group;
import org.groupme.rdf.sesame.ReadWriteUtility;
import org.springframework.beans.BeansException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.WebUtils;

/**
 * created on Nov 2, 2008
 * 
 * This class is the Spring controller for MyGroupMe! stuff. It extends {@link SearchController} because
 * MyGroupMe! has to provide search functionalities...<br/>
 * Further, this controller handles API requests, where a new group should be created.
 * 
 * @author Fabian Abel, <a href="mailto:abel@l3s.de">abel@l3s.de</a>
 * @author last edited by: $Author: fabian $
 * 
 * @version $Revision: 1.6 $ $Date: 2009-06-12 05:41:27 $
 */
public class MyGroupMeController extends SearchController {

	/** Logger for this class and subclasses */
	protected final Log logger = LogFactory.getLog(getClass());
	
	/* (non-Javadoc)
	 * @see net.groupme.controller.SearchController#handleRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView();

		//indicates main MyGroupMe! action:
		String myHome = getStringValue(request, VIEW_VOCABULARY.PARAMETER_MYHOME_VIEW);
		//tags (personal MyGroupMe! search):
		String keywords = getStringValue(request, VIEW_VOCABULARY.PARAMETER_KEYWORD);
		//some sub-actions like queue -> move resource to group
		String subAction = getStringValue(request, VIEW_VOCABULARY.PARAMETER_ACTION);
		String searchFor = getStringValue(request, VIEW_VOCABULARY.PARAMETER_SEARCH_FOR);
		String filterType = getStringValue(request, VIEW_VOCABULARY.PARAMETER_FILTER_RESOURCETYPE);
		String pageID = getStringValue(request, "pageID");
		
		mav.addObject(VIEW_VOCABULARY.PARAMETER_MYHOME_VIEW, myHome);
		mav.addObject(VIEW_VOCABULARY.PARAMETER_KEYWORD, keywords);
		mav.addObject(VIEW_VOCABULARY.PARAMETER_TAG, ObjectFactory.getTagIfExist(keywords));
		mav.addObject(VIEW_VOCABULARY.PARAMETER_FILTER_RESOURCETYPE, filterType);
		
		if(request.getRequestURI().contains(VIEW_VOCABULARY.RESTful_REGISTER_PARTIAL) || request.getRequestURI().contains(VIEW_VOCABULARY.RESTful_ACCOUNT_PARTIAL)){
			mav.setViewName(VIEW_VOCABULARY.VIEW_REGISTER);
		}else{
			mav.setViewName(VIEW_VOCABULARY.VIEW_HOME);
		}
		
		/* API stuff */
		//output?
    	String output = getStringValue(request, API_CONSTANTS.PARAMETER_OUTPUT);
    	if(output == null){//Standard output format is HTML:
    		output = API_CONSTANTS.OUTPUT_HTML;
    	}
    	logger.info("Action: " + myHome + ", subaction: " + subAction + ", ouutput: " + output + ", method: " + request.getMethod());
    	if(API_CONSTANTS.OUTPUT_RDF.equals(output) || API_CONSTANTS.OUTPUT_RDF.equals(HTTPUtilities.detectRequestedOutputFormat(request))
    			|| "POST".equals(request.getMethod())){//all POST requests are interpreted as API calls...
    		//get the group manager that allows to create new groups:
    		GroupManager groupManager = (GroupManager) this.getApplicationContext().getBean(VIEW_VOCABULARY.GROUP_MANGER, GroupManager.class);

    		//check authorization:
    		try{
    			
                OAuthMessage requestMessage = OAuthServlet.getMessage(request, null);
                requestMessage = OAuthProvider.prepare(requestMessage);
                System.out.println(requestMessage);
                
                OAuthAccessor accessor = OAuthProvider.getAccessor(requestMessage);
                if(groupManager.getManager() == null){
        			groupManager.setUserManager(loginUser(accessor));
        		}
                
                //validation will throw an exception if the client application is not authorized:
                OAuthProvider.VALIDATOR.validateMessage(requestMessage, accessor);
                
                //do what the client wants to do:
                if(VIEW_VOCABULARY.VIEW_CREATE_NEW_GROUP.equals(myHome)){
                	createANewGroup(mav, groupManager, request);
                }else if(VIEW_VOCABULARY.VIEW_MYGROUPS.equals(myHome)){
                	viewMyGroups(mav, loginUser(accessor).getUser());
                }
    			return mav;
                
            } catch (Exception e){
            	e.printStackTrace();
                OAuthProvider.handleException(e, request, response, false);
            }
		}
		
		return mav;
	}
    
	/**
	 * API method to create a new group for the user...
	 * @param mav
	 * @param groupManager
	 * @param request
	 * @throws Exception
	 */
	private void createANewGroup(ModelAndView mav, GroupManager groupManager, HttpServletRequest request) throws Exception{
		List<org.groupme.model.light.Group> groupsToCreate = ReadWriteUtility.deserializeFromRDF_XML(getStringValue(request, API_CONSTANTS.RDF_CONTENT));
        for(org.groupme.model.light.Group groupToCreate: groupsToCreate){
        	//create group:
        	groupManager.createNewGroup(groupToCreate.name, groupToCreate.description);
        	
        	//add tags:
        	for(String tag: groupToCreate.tags){
        		groupManager.addTagToActualGroup(tag);
        	}
        	
        	//add resources to group:
        	ResourceVisualization createdResourceVisualization = null;
        	for(org.groupme.model.light.Resource resource: groupToCreate.resources){
        		createdResourceVisualization = groupManager.addResource(resource.name, resource.description, HTTPUtilities.detectContentType(resource.url), HTTPUtilities.prepareSpecialURLs(resource.url).toString());
        		if(createdResourceVisualization != null && createdResourceVisualization.getResource() != null){
        			//add tags of the resource:
        			for(String resourceTag: resource.tags){
        				groupManager.addTagToResource(resourceTag, createdResourceVisualization.getResource().getId());
        			}
        		}
        	}
        }
        //response.setStatus(HttpServletResponse.SC_CREATED);
		mav.setViewName(API_CONSTANTS.VIEW_RDF_GROUP);
	}
	
	/**
	 * API method that lists the groups of the user who is currently logged in and has authorized the 
	 * client application that now sends the request.
	 * @param mav
	 * @param groupManager
	 * @param request
	 * @throws Exception
	 */
	private void viewMyGroups(ModelAndView mav, User u) throws Exception{
		mav.addObject("user", u);
		if(u != null){
			mav.addObject(VIEW_VOCABULARY.PARAMETER_USERNAME, u.getUserName());
		}
		mav.setViewName(API_CONSTANTS.VIEW_RDF_USER);
	}
	/**
	 * Login the user, whose id is stored in the properties of the accessor.
	 * @param accessor the OAuth accessor
	 * @return the user manager instance where the user, whose id is stored in the properties of the accessor, is set
	 */
	private UserManager loginUser(OAuthAccessor accessor){
		UserManager um = (UserManager) this.getApplicationContext().getBean(VIEW_VOCABULARY.USER_MANGER, UserManager.class);
		try {
			um.setUser(ObjectFactory.getUser(new Integer(accessor.getProperty(OAuthProtocol.USER).toString())));
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (UserNotExistingException e) {
			e.printStackTrace();
		}
		
		return um;
	}
}
